package vh.sphynx.util;

import java.io.File;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.util.Strings;

import vh.sphynx.runtime.ExecutionContext;
import vh.sphynx.runtime.impl.XObjectLiteral;
import vh.sphynx.sphynx.CallParameter;
import vh.sphynx.sphynx.SphynxFactory;
import vh.sphynx.sphynx.XFeatureCall;
import vh.sphynx.sphynx.XFunctionDeclaration;

public class SphynxRuntimeUtil {
	
	public static ExecutionContext ActiveContext;
	
	public static final  Map<String, Pattern> patterns = new HashMap<String, Pattern>();
	
	public static Pattern compilePattern(String text, int flag) {
		String varName = "regex:" + Integer.toHexString(text.hashCode());
		Pattern pat = patterns.get(varName);
		if (pat == null) 
			patterns.put(varName, pat = Pattern.compile(text, flag));
		return pat;
	}
	
	public static Constructor<?> findConstructor(Class<?> clazz, Object...args) {
		Constructor<?> res = null;
		for (Constructor<?> ctor: clazz.getConstructors()) {
			Class<?>[] params = ctor.getParameterTypes();
			if (args.length == params.length) {
				boolean matched = true;
				for(int i = 0; i < args.length && matched; i++)
					matched = args[i] == null || params[i].isAssignableFrom(args[i].getClass());
				if (matched)
					return ctor;
			}
		}
		
		return res;
	}
	
	public static String getLocation(boolean shortFilename, ExecutionContext context, EObject element) {
		String result = "";
		try {
			EObject e = element != null ? element : context != null ? context.getEvaluatingExpression() : null;
			if (e != null && context != null && e.eResource() != null) {
				URI uri = e.eResource().getURI();
				String filename = uri.isFile() ? uri.toFileString() : "?";
				if (shortFilename)
					filename = new File(filename).getName();
				Adapter adapter = e.eAdapters().get(0);
				if (adapter instanceof INode) {
					INode node = (INode) adapter;
					int[] loc = resolveNodeLocation(node);
					result = String.format("(%s:%d,%d)", filename, loc[0], loc[1]);
				}				
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
	
	private static int[] resolveNodeLocation(INode node) {
		int offset = node.getOffset();
		INode rootNode = node.getRootNode();
		String leadingText = rootNode.getText().substring(0, offset);
		int line = Strings.countLines(leadingText) + 1;
		int idx = leadingText.lastIndexOf("\n");
		int col = offset - idx - 1;
		
		return new int[] {line, col};
	}
	
	public static XFeatureCall createFeatureCall(XFunctionDeclaration func, boolean allowAnyPass, Map<String, Object> args) {
		XFeatureCall call = SphynxFactory.eINSTANCE.createXFeatureCall();
		
		call.setFeatureElement(func);
		call.setOperatorCall(true);
		for (String key: args.keySet()) {
			CallParameter param = SphynxFactory.eINSTANCE.createCallParameter();
			param.setName(key);
			param.setValue(new XObjectLiteral(args.get(key)));
			call.getParams().add(param);
		}
		if (allowAnyPass) {
			CallParameter param = SphynxFactory.eINSTANCE.createCallParameter();
			param.setInheritedParameters(true);
			call.getParams().add(param);
		}
		return call;
	}
	
	/*public static SimpleDateFormat getDateFormat(ExecutionContext context, String format) {
		ExecutionContext root = context.getRootContext();
		String varName = "sdf:" + Integer.toHexString(format.hashCode());
		IVariable var = root.Variables().getVariable(varName);
		if (var == null) 
			var = root.createVariable(varName, new SimpleDateFormat(format));
		return (SimpleDateFormat) var.getValue();
	}
	
	public static Logger getLogger(ExecutionContext context) {
		Statement s = context.getExecutingStatement();
		String name = s != null ? s.getDeslProgram().getName() : DeslRuntimeUtil.class.getName();
			
		return org.apache.log4j.LogManager.getLogger(name);
	}

	public static IPatternMatchInfo getMatchInfo(IExecutionContext context) {
		return (IPatternMatchInfo) context.Variables().getVariable("@this");
	}
	
	public static void setMatchInfo(IExecutionContext context, IPatternMatchInfo matchInfo) {
		context.Variables().addVariable("@this", matchInfo);
	}
	
	

	public static boolean hasMethod(Object obj, String memberName) {
		Class<?> clazz = (Class<?>) (obj instanceof Class<?> ? obj : obj.getClass());
		for(Method m: clazz.getMethods())
			if (m.getName().equals(memberName))
				return true;
		return false;
	}*/
}
